#![allow(non_snake_case)]
use super::{Message, MessageVariant};
use leptos::{context::Provider,prelude::*};
use std::time::Duration;
use thaw_components::Teleport;
use thaw_utils::class_list;

#[derive(Default, Clone)]
pub enum MessagePlacement {
    #[default]
    Top,
    TopLeft,
    TopRight,
    Bottom,
    BottomLeft,
    BottomRight,
}
impl MessagePlacement {
    fn container_style(&self) -> String {
        match self {
            MessagePlacement::Top => "toast-top toast-center".to_owned(),
            MessagePlacement::TopLeft => "toast-top toast-start".to_owned(),
            MessagePlacement::TopRight => "toast-top toast-end".to_owned(),
            MessagePlacement::Bottom => "toast-bottom toast-center".to_owned(),
            MessagePlacement::BottomLeft => "toast-bottom toast-start".to_owned(),
            MessagePlacement::BottomRight => "toast-bottom toast-end".to_owned(),
        }
    }
}
#[component]
pub fn MessageProvider(
    #[prop(optional)] placement: MessagePlacement,
    children: Children,
) -> impl IntoView {
    let message_list= RwSignal::<Vec<MessageType>>::new(vec![]);

    let handle_after_leave = move |id| {
        message_list.update(move |message_list| {
            let Some(index) = message_list.iter().position(|message| id == message.0) else {
                return;
            };
            message_list.remove(index);
        });
    };

    view! {
        <Provider value=MessageInjection::new(
            message_list,
        )>
            {children()} <Teleport>
                <div class=class_list!["toast", placement.container_style()]>
                    <For
                        each=move || message_list.get()
                        key=|message| message.0
                        children=move |message| {
                            view! { <Message message on_close=handle_after_leave/> }
                        }
                    />

                </div>
            </Teleport>
        </Provider>
    }
}

pub(crate) type MessageType = (usize, String, MessageVariant, MessageOptions);

#[derive(Clone)]
pub struct MessageOptions {
    pub duration: Duration,
    pub closable: bool,
}

impl Default for MessageOptions {
    fn default() -> Self {
        Self {
            duration: Duration::from_secs(3),
            closable: true,
        }
    }
}

#[derive(Clone)]
pub struct MessageInjection {
    message_list: RwSignal<Vec<MessageType>>,
    max_id: usize,
}
impl Copy for MessageInjection {}

impl MessageInjection {
    fn new(message_list: RwSignal<Vec<MessageType>>) -> Self {
        Self {
            message_list,
            max_id: 0,
        }
    }
    fn get_max_id(&self) -> usize {
        self.max_id
    }

    pub fn create(&self, content: impl AsRef<str>, variant: MessageVariant, options: MessageOptions) {
        self.message_list.update(move |message_list| {
            let id = self.get_max_id() + 1;
            message_list.push((id, content.as_ref().to_owned(), variant, options));
        });
    }
}

pub fn use_message() -> MessageInjection {
    expect_context::<MessageInjection>()
}
